package com.chuangke.metadata.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chuangke.admin.data.builder.UserDataBuilder;
import com.chuangke.common.constant.Masks;
import com.chuangke.common.data.builder.DataBuildConfig;
import com.chuangke.common.data.builder.DataBuilder;
import com.chuangke.common.db.page.CkPageQuery;
import com.chuangke.common.idgen.IdManager;
import com.chuangke.metadata.dao.SysBisModelDao;
import com.chuangke.metadata.dao.SysBisModelDetailDao;
import com.chuangke.metadata.entity.SysBisModel;
import com.chuangke.metadata.entity.SysBisModelDetail;
import com.chuangke.metadata.entity.SysGridColumn;
import com.chuangke.metadata.entity.SysGridModel;
import com.chuangke.metadata.service.SysBisModelService;
import com.chuangke.metadata.service.SysGridModelService;

import cn.hutool.core.util.StrUtil;

@Service
@Transactional(rollbackFor = Throwable.class)
public class SysBisModelServiceImpl implements SysBisModelService {

    public static final String CACHE_NAME = "sys_bis_model";

    @Autowired
    private SysBisModelDao sysBisModelDao ;
    @Autowired
    private SysBisModelDetailDao sysBisModelDetailDao ;
    @Autowired
    private SysGridModelService sysGridModelService ;

    @CacheEvict(cacheNames = CACHE_NAME, key = "#model.id")
    public void saveSysBisModelDetail(SysBisModel model) {
        sysBisModelDetailDao.remove(Wrappers.<SysBisModelDetail>lambdaQuery().eq(SysBisModelDetail::getBisModelId, model.getId()));

        if (CollectionUtils.isEmpty(model.getDetails())) {
            return;
        }

        model.getDetails().forEach(d -> {
        	if(StringUtils.isEmpty(IdManager.nextId())) {
        		d.setId(IdManager.nextId()) ;
        	}
            d.setBisModelId(model.getId()) ;
        });

        sysBisModelDetailDao.saveOrUpdateBatch(model.getDetails());
    }

    @Override
    @CacheEvict(cacheNames = CACHE_NAME, key = "#model.id")
    public String save(SysBisModel model) {
        model.setId(IdManager.nextId());
        sysBisModelDao.save(model);
        saveSysBisModelDetail(model);
        return model.getId();
    }

    @Override
    @CacheEvict(cacheNames = CACHE_NAME, key = "#model.id")
    public String saveOrUpdate(SysBisModel model) {
    	sysBisModelDao.saveOrUpdate(model);
        saveSysBisModelDetail(model);
        return model.getId();
    }

    @Override
    @CacheEvict(cacheNames = CACHE_NAME, key = "#model.id")
    public void update(SysBisModel model) {
        sysBisModelDao.updateById(model);
        saveSysBisModelDetail(model);
    }

    @Override
    public void delete(List<String> idList) {
        if(CollectionUtils.isEmpty(idList)) {
            return ;
        }

        idList.forEach(id -> ((SysBisModelService) AopContext.currentProxy()).delete(id));

//        sysBisModelDao.removeBatchByIds(idList);
//        sysBisModelDetailDao
//                .remove(Wrappers.<SysBisModelDetail>lambdaQuery().in(SysBisModelDetail::getBisModelId, idList));
    }

    @Override
    @CacheEvict(cacheNames = CACHE_NAME, key = "#id")
    public void delete(String id) {
        sysBisModelDao.removeById(id);
        sysBisModelDetailDao
                .remove(Wrappers.<SysBisModelDetail>lambdaQuery().eq(SysBisModelDetail::getBisModelId, id));
    }

    @Override
    public SysBisModel load(String id) {
//        SysBisModel model = sysBisModelDao.getById(id);
//        List<SysBisModelDetail> detailList = sysBisModelDetailDao
//                .list(Wrappers.<SysBisModelDetail>lambdaQuery().eq(SysBisModelDetail::getBisModelId, id).orderByAsc(SysBisModelDetail::getSort));

        SysBisModel model = ((SysBisModelService) AopContext.currentProxy()).loadBisModel(id) ;
        
        if(model == null) {
        	return null ;
        }

        model.getDetails().forEach(d ->{
            if(d.getGridModelId()!= null){
                SysGridModel gridModel = sysGridModelService.load(d.getGridModelId());
                d.setGridModel(gridModel);
            }
        });

        List<SysGridColumn> conditionList = new ArrayList<>() ;
        for(SysBisModelDetail detail : model.getDetails()){
            if(detail.getGridModel() == null){
                continue;
            }
            List<SysGridColumn> mxColumns=new ArrayList<>();
            getAllColumns(detail.getGridModel().getColumns(), mxColumns);
            conditionList.addAll(mxColumns.stream().filter(c -> Masks.BOOL_YES.equals(c.getIsCondition())).collect(Collectors.toList())) ;
        }

        model.setConditions(conditionList);
        return model;
    }

    private static void getAllColumns(List<SysGridColumn> columns,List<SysGridColumn> mxColumns){
        columns.forEach(item->{
            List<SysGridColumn> children=item.getChildren();
            if(children!=null&&children.size()>0){
                getAllColumns(children,mxColumns);
            }else{
                mxColumns.add(item);
            }
        });
    }

    @Override
    @Cacheable(cacheNames = CACHE_NAME, key = "#id")
    public SysBisModel loadBisModel(String id) {
        SysBisModel model = sysBisModelDao.getById(id);
        if(model == null) {
        	return null ;
        }
        List<SysBisModelDetail> detailList = sysBisModelDetailDao
                .list(Wrappers.<SysBisModelDetail>lambdaQuery().eq(SysBisModelDetail::getBisModelId, id).orderByAsc(SysBisModelDetail::getSort));
        for(int i=0;i<detailList.size();i++){
            SysGridModel gridModel=sysGridModelService.load(detailList.get(i).getGridModelId());
            detailList.get(i).setGridModel(gridModel);
        }
        model.setDetails(detailList);
        return model ;
    }

    @Override
    public IPage<SysBisModel> page(CkPageQuery page) {
        String fuzzy = (String) page.get("name") ;
        QueryWrapper<SysBisModel> queryWrapper = new QueryWrapper<>() ;
        if(!StrUtil.isBlank(fuzzy)) {
            queryWrapper.lambda().like(SysBisModel::getId, fuzzy).or().like(SysBisModel::getName, fuzzy) ;
        }
        String moduleId=(String) page.get("moduleId") ;
        if(!StrUtil.isBlank(moduleId)) {
            queryWrapper.lambda().eq(SysBisModel::getMoudleId, moduleId);
        }
        queryWrapper.lambda().orderByDesc(SysBisModel::getCreatedAt) ;

        IPage<SysBisModel> result = sysBisModelDao.page(page.getPage(),queryWrapper);
        DataBuilder.of(result.getRecords()).appendBuilder(new UserDataBuilder(), new DataBuildConfig("createdBy", "createdByName"),
                new DataBuildConfig("updatedBy", "updatedByName")).build();

        return result ;
    }

    @Override
    public void deleteDetail(List<String> detailIds) {
        sysBisModelDetailDao.removeBatchByIds(detailIds);
    }

    @Override
    public void saveDetail(SysBisModelDetail detail) {
        if(StringUtils.isEmpty(detail.getId())){
            detail.setId(IdManager.nextId());
        }
        sysBisModelDetailDao.saveOrUpdate(detail);
    }
}
